﻿using Dapper;
using System;
using System.Data;

namespace BJoin.DapperExtension.Postgresql.TypeHandler
{
    public class LongArrayTypeHandler : SqlMapper.TypeHandler<long[]>//should refine to common array
    {
        public override long[] Parse(object value)
        {
            if (value is string)
            {
                var strArray = value.ToString().Replace("{", string.Empty).Replace("}", string.Empty).Split(',');
                var typedValue = Array.ConvertAll(strArray, long.Parse); // looks like Dapper did not indicate the property type to Npgsql, so it defaults to string[] (default CLR type for text[] PostgreSQL type)
                return typedValue;
            }
            return (long[])value;
        }

        public override void SetValue(IDbDataParameter parameter, long[] value)
        {
            parameter.Value = value; // no need to convert to string[] in this direction
        }
    }
    public class ArrayTypeHandler<T> : SqlMapper.TypeHandler<T[]>//support common array
    {
        // looks like Dapper did not indicate the property type to Npgsql, so it defaults to string[] (default CLR type for text[] PostgreSQL type)
        public override T[] Parse(object value)
        {
            if (value is string)
            {
                var strArray = value.ToString().Replace("{", string.Empty).Replace("}", string.Empty).Split(',');
                object[] objValues = null;
                if(typeof(T) == typeof(int))
                    objValues = Array.ConvertAll(strArray, value=>(object)int.Parse(value));
                else if (typeof(T) == typeof(long))
                    objValues = Array.ConvertAll(strArray, value => (object)long.Parse(value));
                else if (typeof(T) == typeof(decimal))
                    objValues = Array.ConvertAll(strArray, value => (object)decimal.Parse(value));
                else if (typeof(T) == typeof(string))
                    objValues = Array.ConvertAll(strArray, value => (object)value?.ToString());
                return GetValue<T[]>(objValues);
            }
            return (T[])value;
        }

        public override void SetValue(IDbDataParameter parameter, T[] value)
        {
            parameter.Value = value; // no need to convert to string[] in this direction
        }
        public static TA GetValue<TA>(object[] inputs)
        {
            if (typeof(TA).IsArray)
            {
                Type elementType = typeof(TA).GetElementType();
                Array array = Array.CreateInstance(elementType, inputs.Length);
                inputs.CopyTo(array, 0);
                TA obj = (TA)(object)array;
                return obj;
            }
            else
            {
                return (TA)inputs[0];
                // will throw on 0-length array, check for length == 0 and return default(T)
                // if do not want exception
            }
        }
    }
}
